/*
* Copyright (c) 2025 Shenzhen Kaihong Digital Industry Development Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

use std::mem::MaybeUninit;

use paste::paste;

use crate::bincode::Decoder;

pub trait Decode: Sized {
    unsafe fn decode_unchecked<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Self;
    fn decode<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Result<Self, D::Error>;
}

macro_rules! impl_decode_for_builtin {
    ($type:ident) => {
        impl Decode for $type {
            unsafe fn decode_unchecked<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Self {
                unsafe { paste! { decoder.[<get_ $type _unchecked>](buf) } }
            }
        
            fn decode<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Result<Self, D::Error> {
                paste! { decoder.[<get_ $type>](buf) }
            }
        }
    };
}

impl_decode_for_builtin!(bool);
impl_decode_for_builtin!(u8);
impl_decode_for_builtin!(u16);
impl_decode_for_builtin!(u32);
impl_decode_for_builtin!(u64);
impl_decode_for_builtin!(i8);
impl_decode_for_builtin!(i16);
impl_decode_for_builtin!(i32);
impl_decode_for_builtin!(i64);
impl_decode_for_builtin!(f32);
impl_decode_for_builtin!(f64);

impl Decode for String {
    unsafe fn decode_unchecked<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Self {
        let len = unsafe { decoder.get_u32_unchecked(buf) };
        let str = unsafe { decoder.get_str_unchecked(buf, len as usize) };
        str.to_string()
    }

    fn decode<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Result<Self, D::Error> {
        let len = decoder.get_u32(buf)?;
        let str = decoder.get_str(buf, len as usize)?;
        Ok(str.to_string())
    }
}

impl<T: Decode, const N: usize> Decode for [T; N] {
    unsafe fn decode_unchecked<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Self {
        let mut arr: [T; N] = unsafe { MaybeUninit::uninit().assume_init() };
        if unty::type_equal::<T, u8>() {
            let bytes = unsafe { decoder.get_bytes_unchecked(buf, N) };
            let ptr = arr.as_mut_ptr() as *mut u8;
            unsafe { std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, N) };
        } else {
            for i in 0..N {
                arr[i] = unsafe { T::decode_unchecked(decoder, buf) };
            }
        }
        arr
    }

    fn decode<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Result<Self, D::Error> {
        let mut arr: [T; N] = unsafe { MaybeUninit::uninit().assume_init() };
        if unty::type_equal::<T, u8>() {
            let bytes = decoder.get_bytes(buf, N)?;
            let ptr = arr.as_mut_ptr() as *mut u8;
            unsafe { std::ptr::copy_nonoverlapping(bytes.as_ptr(), ptr, N) };
        } else {
            for i in 0..N {
                arr[i] = T::decode(decoder, buf)?;
            }
        }
        Ok(arr)
    }
}

impl<T: Decode> Decode for Vec<T> {
    unsafe fn decode_unchecked<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Self {
        let len = unsafe { decoder.get_u32_unchecked(buf) };
        if unty::type_equal::<T, u8>() {
            let bytes = unsafe { decoder.get_bytes_unchecked(buf, len as usize) };
            unsafe { std::mem::transmute(bytes.to_vec()) }
        } else {
            let mut vec = Vec::with_capacity(len as usize);
            for _ in 0..len {
                let item = unsafe { T::decode_unchecked(decoder, buf) };
                vec.push(item);
            }
            vec
        }
    }

    fn decode<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Result<Self, D::Error> {
        let len = decoder.get_u32(buf)?;
        if unty::type_equal::<T, u8>() {
            let bytes = decoder.get_bytes(buf, len as usize)?;
            Ok(unsafe { std::mem::transmute(bytes.to_vec()) })
        } else {
            let mut vec = Vec::with_capacity(len as usize);
            for _ in 0..len {
                let item = T::decode(decoder, buf)?;
                vec.push(item);
            }
            Ok(vec)
        }
    }
}

impl<T: Decode> Decode for Option<T> {
    unsafe fn decode_unchecked<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Self {
        let val = unsafe { decoder.get_bool_unchecked(buf) };
        if val {
            Some(unsafe { T::decode_unchecked(decoder, buf) })
        } else {
            None
        }
    }

    fn decode<D: Decoder>(decoder: &mut D, buf: &[u8]) -> Result<Self, D::Error> {
        let val = decoder.get_bool(buf)?;
        if val {
            Ok(Some(T::decode(decoder, buf)?))
        } else {
            Ok(None)
        }
    }
}
